/*
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    2013 year
 *    Author: Esipenko Aleksey(Alexorleon)
 *    E-Mail: alexorleon@gmail.com
 */
#include "genqrcode.h"
#include <QDateTime>
#include <QDir>
#include <QDebug>

namespace ConstInFunctions {

    const int legthTableAlphanumeric = 45;
    const int characters = 41;
    const int bits = 41;
}

int GenQRCode::GetAlphanumeric(const QChar &_chr){

    // прилетевший символ сравниваем на совпадение, если такого нет, возвращаем -1
    const QChar tableAlphanumeric[ConstInFunctions::legthTableAlphanumeric] = {

        '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
        'P','Q','R','S','T','U','V','W','X','Y','Z',' ','$','%','*','+','-','.','/',':'
    };

    for(int i = 0; i < ConstInFunctions::legthTableAlphanumeric; i++){
        if( _chr == tableAlphanumeric[i]) return i;
    }

    return -1;
}

// Определяем тип данных
int GenQRCode::prepare(){

    //QString modeIndicator = "";                            // Индикатор режима
    bool isNumeric = true;
    bool isAlphanumeric = true;
    //bool isBinaryMode = true;

    // Определение длины сообщения
    lengthMessage = genCode.size();
    qDebug()<<"lengthMessage= "<<lengthMessage;

    while(true){

        for(int i=0; i < lengthMessage; ++i){
            if( !genCode.at(i).isDigit() ){

                isNumeric = false;
                break;
            }
        }
        if(isNumeric){
            binaryMessage = "0001";         // Numeric Mode
            typeQRData = numericType;
            break;
        }

        for(int i = 0; i < lengthMessage; ++i){

            int tmpNum = GetAlphanumeric(genCode.at(i));
            if( tmpNum < 0 ){
                isAlphanumeric = false;
                break;
            }
        }
        if(isAlphanumeric){
            binaryMessage = "0010";         // Alphanumeric Mode
            typeQRData = alphanumericType;
            break;
        }

        binaryMessage = "0100";             // Binary Mode
        typeQRData = binaryType;
        break;

        /*if(!isNumeric && !isAlphanumeric){
            return 3;                       // извините, данного режима нет
            break;
        }*/
    }
    qDebug()<<"typeData= "<<typeQRData;
    qDebug()<<"genCode= "<<genCode;

    // длина сообщения в двоичном представлении
    binaryLengthMessage = QString::number(lengthMessage, 2);
    //qDebug()<<"binaryLengthMessage= "<<binaryLengthMessage;
    qDebug()<<"LengthBits= "<<binaryLengthMessage.size();

    return 0;
}

// определяет версию QR кода
int GenQRCode::DefineVersion(){

    // массивы состоят только из одной версии коррекции ошибок - Q

    const int numeric[ConstInFunctions::characters] = {0,27,48,77,111,144,178,207,259,312,364,
                                                       427,489,580,621,703,775,876,948,1063,1159,
                                                       1224,1358,1468,1588,1718,1804,1933,2085,2181,2358,
                                                       2473,2670,2805,2949,3081,3244,3417,3599,3791,3993};

    const int alphanumeric[ConstInFunctions::characters] = {0,16,29,47,67,87,108,125,157,189,221,
                                                            259,296,352,376,426,470,531,574,644,702,
                                                            742,823,890,963,1041,1094,1172,1263,1322,1429,
                                                            1499,1618,1700,1787,1867,1966,2071,2181,2298,2420};

    const int binaryMode[ConstInFunctions::characters] = {0,11,20,32,46,60,74,86,108,130,151,
                                                          177,203,241,258,292,322,364,394,442,482,
                                                          509,565,611,661,715,751,805,868,908,982,
                                                          1030,1112,1168,1228,1283,1351,1423,1499,1579,1663};

    switch(typeQRData){
    case numericType:
        if( lengthMessage > 3993 ) return 4;
        for(int i = 1; i < ConstInFunctions::characters; i++){
            // если попали точно на версию, сразу присваиваем
            if( lengthMessage == numeric[i] ){
                version = i;
                qDebug()<<"i= "<<i<<"numeric= "<<numeric[i];
                break;
            }else{
                // берем ближайшее подходящее
                if((lengthMessage > numeric[i-1]) &&(lengthMessage <= numeric[i]) ){
                    version = i;
                    qDebug()<<"i= "<<i<<"ближайшее подходящее numeric= "<<numeric[i];
                    break;
                }
            }
        }
        break;
    case alphanumericType:
        if( lengthMessage > 2420 ) return 4;
        for(int i = 1; i < ConstInFunctions::characters; i++){
            // если попали точно на версию, сразу присваиваем
            if( lengthMessage == alphanumeric[i] ){
                version = i;
                qDebug()<<"i= "<<i<<"alphanumeric= "<<alphanumeric[i];
                break;
            }else{
                // берем ближайшее подходящее
                if((lengthMessage > alphanumeric[i-1]) &&(lengthMessage <= alphanumeric[i]) ){
                    version = i;
                    qDebug()<<"i= "<<i<<"ближайшее подходящее alphanumeric= "<<alphanumeric[i];
                    break;
                }
            }
        }
        break;
    case binaryType:
        if( lengthMessage > 1663 ) return 4;
        for(int i = 1; i < ConstInFunctions::characters; i++){
            // если попали точно на версию, сразу присваиваем
            if( lengthMessage == binaryMode[i] ){
                version = i;
                qDebug()<<"i= "<<i<<"binaryMode= "<<binaryMode[i];
                break;
            }else{
                // берем ближайшее подходящее
                if((lengthMessage > binaryMode[i-1]) &&(lengthMessage <= binaryMode[i]) ){
                    version = i;
                    qDebug()<<"i= "<<i<<"ближайшее подходящее binaryMode= "<<binaryMode[i];
                    break;
                }
            }
        }
        break;
    default:
        break;
    }

    qDebug()<<"version= "<<version;
    return 0;
}

// определяем требуемое количество бит для определенной версии
int GenQRCode::DefineNumberBits(){

    if((version >= 1) &&(version <= 9))
    {
        switch(typeQRData)
        {
            case numericType:
                amountBitsForVersion = 10;
                break;
            case alphanumericType:
                amountBitsForVersion = 9;
                break;
            case binaryType:
                amountBitsForVersion = 8;
                break;
            case kanjiType:
                amountBitsForVersion = 8;
                break;
            default:
                break;
        }
    }
    else if((version >= 10) &&(version <= 26))
    {
        switch(typeQRData)
        {
            case numericType:
                amountBitsForVersion = 12;
                break;
            case alphanumericType:
                amountBitsForVersion = 11;
                break;
            case binaryType:
                amountBitsForVersion = 16;
                break;
            case kanjiType:
                amountBitsForVersion = 10;
                break;
            default:
                break;
        }
    }
    else if((version >= 27) &&(version <= 40))
    {
        switch(typeQRData)
        {
            case numericType:
                amountBitsForVersion = 14;
                break;
            case alphanumericType:
                amountBitsForVersion = 13;
                break;
            case binaryType:
                amountBitsForVersion = 16;
                break;
            case kanjiType:
                amountBitsForVersion = 12;
                break;
            default:
                break;
        }
    }
    else
    {
        return 5;
        qDebug()<<"Wrong QRVersion selected. GetNumberBits";
    }

    qDebug()<<"amountBitsForVersion= "<<amountBitsForVersion;
    //qDebug()<<"binaryMessage= "<<binaryMessage;

    // Добавляем недостоющие нули
    int missingBits = amountBitsForVersion - binaryLengthMessage.size();
    //if( missingBits != 0 ){
    if( !missingBits < 1 ){
        binaryMessage += QString(missingBits, '0');
    }
    binaryMessage += binaryLengthMessage;
    //qDebug()<<"binaryMessage="<<binaryMessage;

    return 0;
}

int GenQRCode::DataEncoding(){

    // Кодирование данных
    int isGood = 0;
    switch(typeQRData){
    case numericType:
        isGood = EncodeNumeric();
        break;
    case alphanumericType:
        isGood = EncodeAlphanumeric();
        break;
    case binaryType:
        isGood = EncodeBinaryMode();
        break;
    default:
        isGood = 6;
        break;
    }

    if(isGood != 0) return 6; // ошибка кодирования сообщения

    return 0;
}

// если мало бит, то добавляет нули
const QString GenQRCode::AddingZeros(const int &multi, const int &size){

    int n = 0;
    if(typeQRData == numericType){

        switch(multi){
        case 0:
            n = 10;
            break;
        case 1:
            n = 4;  // кодирование одного оставшегося символа в конце как 4 бита
            break;
        case 2:
            n = 7;
            break;
        default:
            break;
        }
    }else if(typeQRData == alphanumericType){

        switch(multi){
        case 0:
            n = 11;
            break;
        case 1:
            n = 6;      // последний один символ кодируется как 6 бит
            break;
        default:
            break;
        }
    }
    // добавление недостающих нулей
    //QString tmpStr("");
    if(size < n){
        //int mis = n - size;
        QString s = QString(n - size, '0');
        return s;
        //tmpStr.prepend(s);
    }

    return "";
}

// числовое кодирование
int GenQRCode::EncodeNumeric(){

    int multi = 0;
    // определяем кратность трем, сколько в конце символов
    if((lengthMessage % 3) == 0){

    }else{
        if((lengthMessage - 1) % 3 == 0){
            multi = 1;
        }else{
            if((lengthMessage - 2) % 3 == 0){
                multi = 2;
            }else{
                qDebug()<<"number is too short";
                return -1;
            }
        }
    }

    int num = 0;
    QString tmpStr("");
    // кодируется с шагом три, последние символы оставляем на потом
    for( int i = 0; i < lengthMessage - multi; i += 3){
        for( int j = 0; j < 3; j++){
            //num++;
            tmpStr += genCode.at(j+i);
            //if(num == 3){ num = 0; break; }
        }
        // TODO: реализовать проверку нулей в начале
        num = tmpStr.toInt();
        tmpStr = QString::number(num, 2);                     // преобразуем число в двоичное
        tmpStr.prepend(AddingZeros(0, tmpStr.size()));        // добавить нули если нужно TODO: append

        num = 0;
        //qDebug()<<"tmpStr= "<<tmpStr;
        // добавляем к основному
        binaryMessage.append(tmpStr);
        tmpStr.clear();
    }
    if(multi != 0){

        // кодируем в зависимости сколько цифр осталось в конце 1 или 2
        if(multi == 1){

            tmpStr = genCode.at(lengthMessage - 1);
            num = tmpStr.toInt();
            tmpStr = QString::number(num, 2);
            // добавляем нули
            tmpStr.prepend(AddingZeros(multi, tmpStr.size()));  // TODO: append
            num = 0;
            binaryMessage.append(tmpStr);
            //qDebug()<<"tmpStr= "<<tmpStr;
            tmpStr.clear();
        }else{

            tmpStr = genCode.at(lengthMessage - 2);
            tmpStr.append(genCode.at(lengthMessage - 1));
            num = tmpStr.toInt();                               // TODO: проверить первый символ - 0
            tmpStr = QString::number(num, 2);
            tmpStr.prepend(AddingZeros(multi, tmpStr.size()));  // TODO: append
            num = 0;
            binaryMessage.append(tmpStr);
            //qDebug()<<"tmpStr= "<<tmpStr;
            tmpStr.clear();
        }

    }

    return 0;
}

// буквено-числовое кодирование
//кодируем по 2 символа, если нечетное количество то последний символ оставляем на потом.
int GenQRCode::EncodeAlphanumeric(){

    int n = 0;
    if((lengthMessage % 2) != 0 ) n = 1;
    if( lengthMessage < 2) return -1;

    int characterNumber = 0;
    int num = 0;
    bool isSecond = false;
    QString tmpStr("");

    for(int i = 0; i < lengthMessage - n; i += 2){
        for( int j = 0; j < 2; j++){
            // получаем индекс символа
            characterNumber = GetAlphanumeric(genCode.at(j+i));
            // если это уже второе число, то прибавляем его к первому и переводим в двоичное
            if( isSecond == true){                                                            // это второй символ
                num += characterNumber;
                isSecond = false;

                tmpStr = QString::number(num, 2);
                tmpStr.prepend(AddingZeros(0, tmpStr.size()));
                binaryMessage.append(tmpStr);
                //qDebug()<<"tmpStr= "<<tmpStr;
                tmpStr.clear();
                break;
            }
            // специальная формула
            num = 45 * characterNumber;
            isSecond = true;
        }
    }

    // если есть оставшийся симлов, кодируем его отдельно
    if(n != 0){
        num = GetAlphanumeric(genCode.at(lengthMessage-1));
        tmpStr = QString::number(num, 2);
        tmpStr.prepend(AddingZeros(n, tmpStr.size()));
        binaryMessage.append(tmpStr);
        //qDebug()<<"tmpStr= "<<tmpStr;
        tmpStr.clear();
    }

    return 0;
}

// побитовое кодирование
int GenQRCode::EncodeBinaryMode(){

    QString tmpStr("");
    int characterNumber = 0;
    for(int i = 0; i < lengthMessage; i++){
        characterNumber = genCode.at(i).toLatin1();//.toAscii();
        //qDebug()<<"characterNumber= "<<characterNumber;
        //qDebug()<<"characterNumber= "<<characterNumber;
        tmpStr = QString::number(characterNumber, 2);
        // добавление недостающих нулей
        if(tmpStr.size() < 8){
            binaryMessage.append(addZero(tmpStr));
            /*int mis = 8 - this->tmpStr.size();
            QString s = "";
            s += QString(mis, '0');
            this->tmpStr.prepend(s);*/
        }else{
            binaryMessage.append(tmpStr);
        }
    }
    //qDebug()<<"binaryMessage= "<<binaryMessage;
    return 0;
}

// только добавление нулей
const QString GenQRCode::addZero(const QString &str){

    //QString strByte = str;
    QString s = QString(8 - str.size(), '0');
    return s.append(str);
    //return strByte.prepend(s);
}

// корректировка размера по таблице. смотрим сколько бит в версии, если не хватает добавляем.
int GenQRCode::LengthCorrection(){

    const int dataBits[ConstInFunctions::bits] = {0,104,176,272,384,496,608,704,880,1056,1232,
                                                  1440,1648,1952,2088,2360,2600,2936,3176,3560,3880,
                                                  4096,4544,4912,5312,5744,6032,6464,6968,7288,7880,
                                                  8264,8920,9368,9848,10288,10832,11408,12016,12656,13328};


    //this->binaryMessage.remove(QChar(' '));     // TODO: потом удалить добавление пробелов в программе
    int num = binaryMessage.size();

    if( num > dataBits[version] ) return -1;

    if( dataBits[version] - num == 4){
        binaryMessage.append("0000");
        return 0;
    }else{
        if( dataBits[version] - num < 4 ){
            binaryMessage.append(QString(dataBits[version] - num, '0'));
            return 0;
        }else{    // если остаток больше 4, то нужно корректировать длину
            binaryMessage.append("0000");
            num += 4;   // прибавляем 4 т.к. добавили 4 нуля
        }
    }

    // разбиваем по 8 бит, если не кратно 8, то добавляем нули
    int n = num / 8;
    n = n * 8;
    n = num - n;
    n = 8 - n;
    binaryMessage.append(QString(n, '0'));
    num += n;
    // шаблоны для чередования в конце сообщения
    const QString _1 = "11101100";
    const QString _2 = "00010001";
    n = dataBits[version] - num;
    n = n / 8;
    // чередуем по четности и нечетности
    for(int i = 0; i < n; i++){
        if( i % 2 == 0){
            binaryMessage.append(_1);
        }else{
            binaryMessage.append(_2);
        }
    }

    if( binaryMessage.size() != dataBits[version] ) return -1;

    qDebug()<<"binaryMessage.size= "<<binaryMessage.size();
    //qDebug()<<"binaryMessage= "<<binaryMessage;
    qDebug()<<"dataBits[version]= "<<dataBits[version];
    return 0;
}

// генерация кода Рида-Соломона
int GenQRCode::ReedSolomon(){
    // x^8 + x^4 + x^3 + x^2 + 1 -> 100011101 - Primitive polynomial
    const int qrCodeField = 0x011D; // 285
    const int fieldCount = 256;

    // TODO: здесь должна быть обработка ошибок при выделении памяти
    int* logTable = new int[fieldCount];            // таблица поля Галуа
    int* antiLogTable = new int[fieldCount];        // обратная таблица поля Галуа

    // step 1 генерация полей галуа
    int mask = 1;

    for(int i = 0; i < fieldCount; i++){
        logTable[i] = mask;

        mask = mask << 1;

        if(mask >= fieldCount){
            mask ^= qrCodeField;
            mask &= fieldCount - 1;
        }
    }
    antiLogTable[0] = -1;
    logTable[255] = 0;      // данные из разных книг различаются, возможно нужно указать число больше 256

    // обратное поле
    for(int i = 0; i < fieldCount - 1; i++){
        antiLogTable[logTable[i]] = i;
    }

    // количество блоков в группах
    const short int codeBlocks[200] = {
        13, 1, 13, 0, 0,
        22, 1, 22, 0, 0,
        18, 2, 17, 0, 0,
        26, 2, 24, 0, 0,
        18, 2, 15, 2, 16,
        24, 4, 19, 0, 0,
        18, 2, 14, 4, 15,
        22, 4, 18, 2, 19,
        20, 4, 16, 4, 17,
        24, 6, 19, 2, 20,
        28, 4, 22, 4, 23,
        26, 4, 20, 6, 21,
        24, 8, 20, 4, 21,
        20, 11, 16, 5, 17,
        30, 5, 24, 7, 25,
        24, 15, 19, 2, 20,
        28, 1, 22, 15, 23,
        28, 17, 22, 1, 23,
        26, 17, 21, 4, 22,
        30, 15, 24, 5, 25,
        28, 17, 22, 6, 23,
        30, 7, 24, 16, 25,
        30, 11, 24, 14, 25,
        30, 11, 24, 16, 25,
        30, 7, 24, 22, 25,
        28, 28, 22, 6, 23,
        30, 8, 23, 26, 24,
        30, 4, 24, 31, 25,
        30, 1, 23, 37, 24,
        30, 15, 24, 25, 25,
        30, 42, 24, 1, 25,
        30, 10, 24, 35, 25,
        30, 29, 24, 19, 25,
        30, 44, 24, 7, 25,
        30, 39, 24, 14, 25,
        30, 46, 24, 10, 25,
        30, 49, 24, 10, 25,
        30, 48, 24, 14, 25,
        30, 43, 24, 22, 25,
        30, 34, 24, 34, 25
    };

    // берем данные из таблицы
    int codewords = codeBlocks[(version - 1) * 5];    // размер блока под коррекцию ошибок
    int countGroup_1 = codeBlocks[(version - 1) * 5 + 1];
    int countFirstBlock = codeBlocks[(version - 1) * 5 + 2];
    int countGroup_2 = codeBlocks[(version - 1) * 5 + 3];
    int countSecondBlock = codeBlocks[(version - 1) * 5 + 4];

    // step 2 генерация порождающего полинома
    const int nn = 255;      // 2**8-1 длина кодового слова
    int kk = nn - codewords;   // kk = nn-codewords степень g(x) = 2*codewords - информационное слово 242
    int gg[codewords + 1];      // таблица порождающего полинома
    int b0 = 0;         // g(x) имеет корни g(x)**b0, g(x)**(b0+1), ... ,g(x)^(b0+2*codewords-1)

    gg[0] = logTable[b0];
    gg[1] = 1;                                 // g(x) =(X+g(x)**b0) - инициализация
    for(int i=2; i <= codewords; i++){
        gg[i] = 1;
        // заполнение порождающего полинома(gg[0]+gg[1]*x + ... +gg[i]x^i) до(g(x)**(b0+i-1) + x)
        for(int j=i-1; j>0; j--)
            if(gg[j] != 0)  gg[j] = gg[j-1]^ logTable[((antiLogTable[gg[j]])+b0+i-1)%nn];
            else gg[j] = gg[j-1];

        gg[0] = logTable[((antiLogTable[gg[0]])+b0+i-1)%nn];     /* gg[0] никогда не равен нулю */
    }
    // порождающий полином gg в удобном виде
    for(int i=0; i </*=*/ codewords; i++) gg[i] = antiLogTable[gg[i]];

    // массив основных данных, массив кода корректировки
    int data[kk], bb[codewords];

    // TODO: здесь должна быть обработка ошибок при выделении памяти
    // Создаются 4 разных массива для работы с определенным блоком,
    // так как методы чередования символов разные для почти каждой версии
    int** arrayFirstGroup = new int*[countGroup_1];
    for(int i = 0; i < countGroup_1; i++){
        arrayFirstGroup[i] = new int[countFirstBlock];
    }
    int** arraySecondGroup = new int*[countGroup_2];
    for(int i = 0; i < countGroup_2; i++){
        arraySecondGroup[i] = new int[countSecondBlock];
    }

    int** correctArrayFirstGroup = new int*[countGroup_1];
    for(int i = 0; i < countGroup_1; i++){
        correctArrayFirstGroup[i] = new int[codewords];
    }
    int** correctArraySecondGroup = new int*[countGroup_2];
    for(int i = 0; i < countGroup_2; i++){
        correctArraySecondGroup[i] = new int[codewords];
    }

    // инициализация
    for(int i = 0; i < countGroup_1; i++){
        for(int j = 0; j < countFirstBlock; j++){
            arrayFirstGroup[i][j] = 0;
        }
    }
    for(int i = 0; i < countGroup_2; i++){
        for(int j = 0; j < countSecondBlock; j++){
            arraySecondGroup[i][j] = 0;
        }
    }

    for(int i = 0; i < countGroup_1; i++){
        for(int j = 0; j < codewords; j++){
            correctArrayFirstGroup[i][j] = 0;
        }
    }
    for(int i = 0; i < countGroup_2; i++){
        for(int j = 0; j < codewords; j++){
            correctArraySecondGroup[i][j] = 0;
        }
    }

    bool isEnd = false;
    int tempCountGroup = countGroup_1;      // инициализайия первой группой
    int tempCountBlock = countFirstBlock;   // инициализайия первым блоком
    short int bloc = tempCountBlock * 8;    // для взятия каждого блока
    short int counterBloc = 0;

    QString tempByteString = "";
    int numByte = 0;
    bool ok;
    int positionData = tempCountBlock - 1;

    do{
        // step 3 подготовка сообщения для кодирования
        for(int i = 0; i < kk; i++) data[i] = 0;

        // цикл кодирования по блокам
        for(int currentGroup = 0; currentGroup < tempCountGroup; currentGroup++){
            for(int t = counterBloc; t < bloc; t += 8){   // взятие из сообщения очередного блока
                for(int jj = 0; jj < 8; jj++){
                    tempByteString.append(binaryMessage.at(jj+t));
                }

                numByte = tempByteString.toInt(&ok,2);
                data[positionData] = numByte;

                // заполняем только нужную группу
                if(!isEnd){
                    arrayFirstGroup[currentGroup][positionData] = numByte;    // заполнение first group
                }
                if(isEnd){
                    arraySecondGroup[currentGroup][positionData] = numByte;    // заполнение second group
                }

                positionData--;
                tempByteString.clear();
            }
            positionData = tempCountBlock - 1;  // сбрасываем счетчик для текущего блока

            // step 4 кодирование сообщения
            int feedback = 0;

            for(int i = 0; i < codewords; i++) bb[i] = 0;

            for(int i=kk-1; i>=0; i--){
                feedback = antiLogTable[data[i] ^ bb[codewords-1]];

                if(feedback != -1){                               // не равно нулю в таблице
                    for(int j=codewords-1; j>0; j--)
                        if(gg[j] != -1){
                            bb[j] = bb[j-1] ^ logTable[(gg[j]+feedback)%nn];
                        }else{
                            bb[j] = bb[j-1];
                        }

                    bb[0] = logTable[(gg[0]+feedback)%nn];
                }
                else // слагаемое равно нулю, производится однобайтовый сдвиг
                {
                    for(int j = codewords-1; j>0; j--) bb[j] = bb[j-1];
                    bb[0] = 0;
                }
            }
            if(!isEnd){
                for(int i = 0; i < codewords; i++){
                    correctArrayFirstGroup[currentGroup][i] = bb[i];    // заполнение correction first group
                }
            }

            if(isEnd){
                for(int i = 0; i < codewords; i++){
                    correctArraySecondGroup[currentGroup][i] = bb[i];    // заполнение correction second group
                }
            }
            counterBloc = bloc;
            bloc += tempCountBlock * 8;     // наращиваем для получения следующего блока
        }

        if(isEnd == true) break;
        if(countGroup_2 != 0){             // необходимо  кодирование второй группы

            bloc -= tempCountBlock * 8;     // откатываем назад, убираем лишнее приращение
            tempCountGroup = countGroup_2;
            tempCountBlock = countSecondBlock;  // теперь будут обрабатываться следующие блоки
            bloc += tempCountBlock * 8;

            positionData = countSecondBlock - 1;
            isEnd = true;  // обработка второй группы
        }else
            break;

    }while(true);

    QString strByte = "";
    QString tempStrWord = "";
    short int dig = 0;
    if(countSecondBlock == 0){
        tempCountBlock = countFirstBlock;       // инициализайия 1 блоком
    }else{
        tempCountBlock = countSecondBlock;      // инициализайия 2 блоком
        dig = 1;
    }

    for(int i = tempCountBlock -1; i >= 0; i--){
        if(i != 0){
            for(int firstGroup = 0; firstGroup < countGroup_1; firstGroup++){

                strByte = QString::number(arrayFirstGroup[firstGroup][i-dig], 2);
                // добавление недостающих нулей
                if(strByte.size() < 8){
                    tempStrWord.append(addZero(strByte));
                }else{
                    tempStrWord.append(strByte);
                }
            }
            finishedBinaryMessage.append(tempStrWord);
            tempStrWord.clear();
        }else{
            if(countFirstBlock > countSecondBlock){
                for(int firstGroup = 0; firstGroup < countGroup_1; firstGroup++){

                    strByte = QString::number(arrayFirstGroup[firstGroup][i-dig], 2);
                    // добавление недостающих нулей
                    if(strByte.size() < 8){
                        tempStrWord.append(addZero(strByte));
                    }else{
                        tempStrWord.append(strByte);
                    }
                }
                finishedBinaryMessage.append(tempStrWord);
                tempStrWord.clear();
            }
        }

        tempStrWord.clear();
        if(countSecondBlock != 0){
            for(int secondGroup = 0; secondGroup < countGroup_2; secondGroup++){

                strByte = QString::number(arraySecondGroup[secondGroup][i], 2);
                // добавление недостающих нулей
                if(strByte.size() < 8){
                    tempStrWord.append(addZero(strByte));
                }else{
                    tempStrWord.append(strByte);
                }
            }
            finishedBinaryMessage.append(tempStrWord);
            tempStrWord.clear();
        }
    }

    tempStrWord.clear();
    for(int i = codewords -1; i >= 0; i--){

            for(int firstGroup = 0; firstGroup < countGroup_1; firstGroup++){

                strByte = QString::number(correctArrayFirstGroup[firstGroup][i], 2);
                // добавление недостающих нулей
                if(strByte.size() < 8){
                    tempStrWord.append(addZero(strByte));
                }else{
                    tempStrWord.append(strByte);
                }
            }
            finishedBinaryMessage.append(tempStrWord);
            tempStrWord.clear();

        if(countSecondBlock != 0){
            for(int secondGroup = 0; secondGroup < countGroup_2; secondGroup++){

                strByte = QString::number(correctArraySecondGroup[secondGroup][i], 2);
                // добавление недостающих нулей
                if(strByte.size() < 8){
                    tempStrWord.append(addZero(strByte));
                }else{
                    tempStrWord.append(strByte);
                }
            }
            finishedBinaryMessage.append(tempStrWord);
            tempStrWord.clear();
        }
    }
    // TODO: добавить недостающте нули

    // освобождение памяти
    delete[] logTable;
    delete[] antiLogTable;

    for(int i = 0; i < countGroup_1; i++){
        delete[] arrayFirstGroup[i];
    }
    for(int i = 0; i < countGroup_2; i++){
        delete[] arraySecondGroup[i];
    }

    for(int i = 0; i < countGroup_1; i++){
        delete[] correctArrayFirstGroup[i];
    }
    for(int i = 0; i < countGroup_2; i++){
        delete[] correctArraySecondGroup[i];
    }
    delete arrayFirstGroup;
    delete arraySecondGroup;
    delete correctArrayFirstGroup;
    delete correctArraySecondGroup;

    return 0;
}

// заполнение матрицы данными
int GenQRCode::ImageGeneration(){

    int range =(version - 1) * 4 + 21;       // размер матрицы
    // создание матрицы
    int** qrMatrix = new int*[range];
    int** qrMatrixCopy = new int*[range];           // копия матрицы для подбора маски
    for(int i = 0; i < range; i++){
        qrMatrix[i] = new int[range];
        qrMatrixCopy[i] = new int[range];
    }

    for(int i = 0; i < range; i++){
        for(int j = 0; j < range; j++){
            qrMatrix[i][j] = 9;
            qrMatrixCopy[i][j] = 9;
        }
    }

    int r = range - 8;
    // блокирование бит, созданиe ключей для обнаружения
    // left
    int count = 8;
    int num = 0;
    int sum = 0;
    while(true){
        for(int i = 0 + sum; i < count; i++)
            for(int j = 0 + sum; j < count; j++){
                qrMatrix[i][j] = num;
            }
        if(sum == 2) break;
        if(count == 8){
            count--;
            num = 1;
        }else{
            if(count == 7){
                count--;
                num = 0;
                sum++;
            }else{
                if(count == 6){
                    count--;
                    num = 1;
                    sum++;
                }
            }
        }
    }

    // right
    count = 8;
    num = 0;
    sum = 0;
    int sum_2 = 0;
    while(true){
        for(int i = r + sum; i < range - sum_2; i++)
            for(int j = 0 + sum_2; j < count; j++){
                qrMatrix[i][j] = num;
            }
        if(sum == 3) break;
        if(count == 8){
            count--;
            sum++;
            num = 1;
        }else{
            if(count == 7){
                count--;
                num = 0;
                sum++;
                sum_2++;
            }else{
                if(count == 6){
                    count--;
                    num = 1;
                    sum++;
                    sum_2++;
                }
            }
        }
    }

    // down
    count = 8;
    num = 0;
    sum = 0;
    sum_2 = 0;
    while(true){
        for(int i = 0 + sum_2; i < count; i++)
            for(int j = r + sum; j < range - sum_2; j++){
                qrMatrix[i][j] = num;
            }
        if(sum == 3) break;
        if(count == 8){
            count--;
            num = 1;
            sum++;
        }else{
            if(count == 7){
                count--;
                num = 0;
                sum++;
                sum_2++;
            }else{
                if(count == 6){
                    count--;
                    num = 1;
                    sum++;
                    sum_2++;
                }
            }
        }
    }

    // Black pixel
    qrMatrix[8][r] = 1;

    // блокирование бит type information
    // horizontal
    for(int i = 0; i < range; i++){
        qrMatrix[i][8] = 1;
        if(i == 5) i++;
        if(i == 7) i += r - 8;
    }
    // vertical
    for(int j = 0; j < range; j++){
        qrMatrix[8][j] = 1;
        if(j == 5) j++;
        if(j == 8) j += r - 8;
    }

    // Version Information
    // для версий не ниже седьмой
    if(version >= 7){
        const QString versionInfo[34] = {
            "001010010011111000",

           //"001000010110111100",
            "000111101101000100", //старое 8
            "100110010101100100",
            "011001011001010100",

            "001011101111110110",
            //"011011111101110100", старое 11
            "001000110111001100",
            "111000100001101100",
            "010110000011011100",
            "000101001001111100",
            "000111101101000010",
            "010111010001100010",
            "111010000101010010",
            "001001100101110010",
            "011001011001001010",
            "011000001011101010",
            "100100110001011010",
            "000110111111111010",
            "001000110111000110",
            "000100001111100110",
            "110101011111010110",
            "000001110001110110",
            "010110000011001110",
            "001111110011101110",
            "101011101011011110",
            "000000101001111110",
            "101010111001000001",
            "000001111011100001",
            "010111010001010001",
            "011111001111110001",
            "110100001101001001",
            "001110100001101001",
            "001001100101011001",
            "010000010101111001",
            "100101100011000101"
        };
        QString tempVersionInfo = versionInfo[version - 7];
        int countMask = 0;
        // right
        for(int j = 0; j < 6; j++)
            for(int i = range - 11; i < range - 8; i++){
                if(tempVersionInfo.at(countMask) == '1'){

                    qrMatrix[i][j] = 1;
                }else qrMatrix[i][j] = 0;
                countMask++;
            }
        countMask = 0;
        // down
        for(int i = 0; i < 6; i++)
            for(int j = range - 11; j < range - 8; j++){
                if(tempVersionInfo.at(countMask) == '1'){

                    qrMatrix[i][j] = 1;
                }else qrMatrix[i][j] = 0;
                countMask++;
            }
    }
    // Adjustment pattern
    const short int alignmentPos[39][7] = {
        {6, 18, 0, 0, 0, 0, 0},
        {6, 22, 0, 0, 0, 0, 0},
        {6, 26, 0, 0, 0, 0, 0},
        {6, 30, 0, 0, 0, 0, 0},
        {6, 34, 0, 0, 0, 0, 0},
        {6, 22, 38, 0, 0, 0, 0},
        {6, 24, 42, 0, 0, 0, 0},
        {6, 26, 46, 0, 0, 0, 0},
        {6, 28, 50, 0, 0, 0, 0},
        {6, 30, 54, 0, 0, 0, 0},
        {6, 32, 58, 0, 0, 0, 0},
        {6, 34, 62, 0, 0, 0, 0},
        {6, 26, 46, 66, 0, 0, 0},
        {6, 26, 48, 70, 0, 0, 0},
        {6, 26, 50, 74, 0, 0, 0},
        {6, 30, 54, 78, 0, 0, 0},
        {6, 30, 56, 82, 0, 0, 0},
        {6, 30, 68, 86, 0, 0, 0},
        {6, 34, 62, 90, 0, 0, 0},
        {6, 28, 50, 72, 94, 0, 0},
        {6, 26, 50, 74, 98, 0, 0},
        {6, 30, 54, 78, 102, 0, 0},
        {6, 28, 54, 80, 106, 0, 0},
        {6, 32, 58, 84, 110, 0, 0},
        {6, 30, 58, 86, 114, 0, 0},
        {6, 34, 62, 90, 118, 0, 0},
        {6, 26, 50, 74, 98, 122, 0},
        {6, 30, 54, 78, 102, 126, 0},
        {6, 26, 52, 78, 104, 130, 0},
        {6, 30, 56, 82, 108, 134, 0},
        {6, 34, 60, 86, 112, 138, 0},
        {6, 30, 58, 86, 114, 142, 0},
        {6, 34, 62, 90, 118, 146, 0},
        {6, 30, 54, 78, 102, 126, 150},
        {6, 24, 50, 76, 102, 128, 154},
        {6, 28, 54, 80, 106, 132, 158},
        {6, 32, 58, 84, 110, 136, 162},
        {6, 26, 54, 82, 110, 138, 166},
        {6, 30, 58, 86, 114, 142, 170}
    };
    // блокирование бит Adjustment pattern
    const int versia = version;

    if(versia != 1){

        for(int i = 0; i < 7; i++){
            if( alignmentPos[versia - 2][i] == 0 ) continue;

            for(int j = 0; j < 7; j++){
                if( alignmentPos[versia - 2][j] == 0 ) continue;
                if(qrMatrix[ alignmentPos[ versia - 2 ][i]][ alignmentPos[ versia - 2 ][j]] == 9 ){

                    for(int x = alignmentPos[ versia - 2 ][i] - 2; x < alignmentPos[ versia - 2 ][i] + 3; x++)
                        for(int y = alignmentPos[ versia - 2 ][j] - 2; y < alignmentPos[ versia - 2 ][j] + 3; y++){
                            qrMatrix[x][y] = 1;
                        }
                    for(int x = alignmentPos[ versia - 2 ][i] - 1; x < alignmentPos[ versia - 2 ][i] + 2; x++)
                        for(int y = alignmentPos[ versia - 2 ][j] - 1; y < alignmentPos[ versia - 2 ][j] + 2; y++){
                            qrMatrix[x][y] = 0;
                        }
                    qrMatrix[ alignmentPos[ versia - 2 ][i]][ alignmentPos[ versia - 2 ][j]] = 1;
                }
            }
        }
    }

    // Timing pattern
    for(int i = 8; i < r; i++){
        if((i % 2) == 0){
            qrMatrix[i][6] = 1;
        } else qrMatrix[i][6] = 0;
    }
    for(int j = 8; j < r; j++){
        if((j % 2) == 0){
            qrMatrix[6][j] = 1;
        } else qrMatrix[6][j] = 0;
    }

    // Type Information
    const QString typeInf[8] = {
        "011010101011111",
        "011000001101000",
        "011111100110001",
        "011101000000110",
        "010010010110100",
        "010000110000011",
        "010111011011010",
        "010101111101101"
    };

    // модель маски для 3 правила
    const int rule3Model1[15] = {0,0,0,0,1,0,1,1,1,0,1,0,0,0,0};
    const int rule3Model2[11] = {1,0,1,1,1,0,1,0,0,0,0};
    const int rule3Model3[11] = {0,0,0,0,1,0,1,1,1,0,1};

    // выбор оптимальной маски и заполнение данными
    int viewMask = 0;                                   // счетчик для выбора маски
    int optimalMask = 0;
    int optimalPenalty = 0;
    const float countPixels = range * range;
    const int finishedBinaryMessageSize = finishedBinaryMessage.size();
    qDebug()<<"finishedBinaryMessageSize= "<<finishedBinaryMessage.size();
    qDebug()<<"select optimal mask";
    for(int nMask = 0; nMask < 9; nMask++){           // проход по каждой из 8 масок и выбор окончательного варианта

        int penalty = 0;                                // сумма нарушений
        int column = range - 1;
        int countBin = 0;
        int zeroMask = 0;                               // возвращаемое значение из формулы маски
        int approaches = column/4;
        // восстановление первоначального состояния матрицы-копии
        for(int i = 0; i < range; i++){
            for(int j = 0; j < range; j++){
                qrMatrixCopy[i][j] = qrMatrix[i][j];
            }
        }

        //qDebug()<<"Step 1";
        // type information по выбраной маске
        QString mask = typeInf[viewMask];
        // Type information
        // horizontal
        int countMask = 0;
        for(int i = 0; i < range; i++){
            if(mask.at(countMask) == '1'){
                qrMatrixCopy[i][8] = 1;
            } else qrMatrixCopy[i][8] = 0;

            countMask++;
            if(i == 5) i++;
            if(i == 7) i += r - 8;
        }
        //qDebug()<<"Step 2";
        // vertical
        countMask = 14;
        for(int j = 0; j < range; j++){
            if(mask.at(countMask) == '1'){
                qrMatrixCopy[8][j] = 1;
            } else qrMatrixCopy[8][j] = 0;

            countMask--;
            if(j == 5) j++;
            if(j == 8) j += r - 8;
        }

        //qDebug()<<"Step 3";
        // заполняем матрицу данными
        for(int k = 0; k < approaches; k++){          // количество проходов
            //qDebug()<<"down up";
            for(int j = range; j >= 0; j--){
                if((qrMatrixCopy[column][j] != 9) && (qrMatrixCopy[column - 1][j] != 9)){
                    //qrMatrixCopy[column][j] = 8;
                    //qrMatrixCopy[column-1][j] = 7;
                    continue;
                }
                //qDebug()<<"Step 4";
                // начинаем обход Adjustment pattern
                if((qrMatrixCopy[column][j] != 9) &&(qrMatrixCopy[column - 1][j] == 9)){

                    zeroMask = ChoiceMask(viewMask, column - 1, j);
                    if(zeroMask == 0){
                        if(finishedBinaryMessage.at(countBin) == '1') qrMatrixCopy[column - 1][j] = 0;
                        if(finishedBinaryMessage.at(countBin) == '0') qrMatrixCopy[column - 1][j] = 1;
                    }else{
                        if(finishedBinaryMessage.at(countBin) == '1') qrMatrixCopy[column - 1][j] = 1;
                        if(finishedBinaryMessage.at(countBin) == '0') qrMatrixCopy[column - 1][j] = 0;
                    }
                    countBin++;
                    continue;
                }
                //qDebug()<<"Step 5";

                for(int i = column; i >= column - 1; i--){
                    zeroMask = ChoiceMask(viewMask, i, j);
                    if(zeroMask == 0){
                        if(finishedBinaryMessage.at(countBin) == '1') qrMatrixCopy[i][j] = 0;
                        if(finishedBinaryMessage.at(countBin) == '0') qrMatrixCopy[i][j] = 1;
                    }else{
                        if(finishedBinaryMessage.at(countBin) == '1') qrMatrixCopy[i][j] = 1;
                        if(finishedBinaryMessage.at(countBin) == '0') qrMatrixCopy[i][j] = 0;
                    }
                    countBin++;
                }
                //qDebug()<<"Step 6";

            }
            if(column == 8) column--;
            column -= 2;
            //qDebug()<<"up down";
            for(int j = 0; j < range; j++){
                // если текущая позиция занята, идем к следующей
                if((qrMatrixCopy[column][j] != 9) &&(qrMatrixCopy[column - 1][j] != 9)){
                    //qrMatrixCopy[column][j] = -5;
                    //qrMatrixCopy[column-1][j] = -6;
                    continue;
                }
                // позиция не занята, расчитываем бит и заполняем позицию
                //qDebug()<<"Step 7";
                // начинаем обход Adjustment pattern
                if((qrMatrixCopy[column][j] != 9) &&(qrMatrixCopy[column - 1][j] == 9)){

                    zeroMask = ChoiceMask(viewMask, column - 1, j);
                    if(zeroMask == 0){
                        if(finishedBinaryMessage.at(countBin) == '1') qrMatrixCopy[column - 1][j] = 0;
                        if(finishedBinaryMessage.at(countBin) == '0') qrMatrixCopy[column - 1][j] = 1;
                    }else{
                        if(finishedBinaryMessage.at(countBin) == '1') qrMatrixCopy[column - 1][j] = 1;
                        if(finishedBinaryMessage.at(countBin) == '0') qrMatrixCopy[column - 1][j] = 0;
                    }
                    countBin++;
                    continue;
                }
                //qDebug()<<"Step 8";

                //qDebug()<<"column= "<<column;
                for(int i = column; i >= column - 1; i--){
                    zeroMask = ChoiceMask(viewMask, i, j);
                    if(countBin == finishedBinaryMessageSize) break; //TODO:
                    if(zeroMask == 0){
                        if(finishedBinaryMessage.at(countBin) == '1') qrMatrixCopy[i][j] = 0;
                        if(finishedBinaryMessage.at(countBin) == '0') qrMatrixCopy[i][j] = 1;
                    }else{
                        if(finishedBinaryMessage.at(countBin) == '1') qrMatrixCopy[i][j] = 1;
                        if(finishedBinaryMessage.at(countBin) == '0') qrMatrixCopy[i][j] = 0;
                    }
                    countBin++;
                    //qDebug()<<"countBin= "<<countBin;
                }
                //qDebug()<<"Step 9";
            }
            column -= 2;
            //qDebug()<<"!!!!!!!COLUMN= "<<column;
        }
        qDebug()<<"MASK";
        // теперь необходимо рассчитать значение маски по 4 алгоритмам и запомнить результат
        if(viewMask != 8){    // чтобы не осуществлялся последний проход

            // rule 1
            // horizontal
            for(int j = 0; j < range; j++){
                for(int i = 0; i < range - 4; i++ ){
                    if((qrMatrixCopy[i][j] == qrMatrixCopy[i+1][j])
                            &&(qrMatrixCopy[i][j] == qrMatrixCopy[i+2][j])
                            &&(qrMatrixCopy[i][j] == qrMatrixCopy[i+3][j])
                            &&(qrMatrixCopy[i][j] == qrMatrixCopy[i+4][j])){

                        int marker = qrMatrixCopy[i][j];                // маркер - 0 или 1
                        penalty += 3;
                        for(int next = i+5; next < range; next++){
                            if(qrMatrixCopy[next][j] == marker){
                                penalty++;
                                i = next-1;
                            }else{
                                i = next-1;
                                break;
                            }
                        }
                    }
                }
            }
            // vertical
            for(int i = 0; i < range; i++){
                for(int j = 0; j < range - 4; j++ ){
                    if((qrMatrixCopy[i][j] == qrMatrixCopy[i][j+1])
                            &&(qrMatrixCopy[i][j] == qrMatrixCopy[i][j+2])
                            &&(qrMatrixCopy[i][j] == qrMatrixCopy[i][j+3])
                            &&(qrMatrixCopy[i][j] == qrMatrixCopy[i][j+4])){

                        int marker = qrMatrixCopy[i][j];                // маркер - 0 или 1
                        penalty += 3;
                        for(int next = j+5; next < range; next++){
                            if(qrMatrixCopy[i][next] == marker){
                                penalty++;
                                j = next-1;
                            }else{
                                j = next-1;
                                break;
                            }
                        }
                    }
                }
            }

            // rule 2
            for(int j = 0; j < range - 1; j++){
                for(int i = 0; i < range - 1; i++ ){
                    int marker = qrMatrixCopy[i][j];                // маркер - 0 или 1
                    if((qrMatrixCopy[i][j] == marker)
                            &&(qrMatrixCopy[i+1][j] == marker)
                            &&(qrMatrixCopy[i][j+1] == marker)
                            &&(qrMatrixCopy[i+1][j+1] == marker)){
                        penalty += 3;
                    }
                }
            }

            // rule 3
            // horizontal
            int match = 0;
            for(int j = 0; j < range; j++){
                for(int i = 0; i < range - 14; i++ ){
                    for(int rule = 0; rule < 15; rule++){
                        if(rule3Model1[rule] == qrMatrixCopy[i+rule][j]) match++;  // сверяем элементы маски
                    }
                    // если совпала вся строка
                    if(match == 15){
                        penalty += 40;
                    }
                    match = 0;
                }
            }
            int match2 = 0;
            for(int j = 0; j < range; j++){
                for(int i = 0; i < range - 10; i++ ){
                    for(int rule = 0; rule < 11; rule++){
                        if(rule3Model2[rule] == qrMatrixCopy[i+rule][j]) match++;  // сверяем элементы маски
                        if(rule3Model3[rule] == qrMatrixCopy[i+rule][j]) match2++;
                    }
                    // если совпала вся строка
                    if((match == 11) ||(match2 == 11)){
                        penalty += 40;
                    }
                    match = 0;
                    match2 = 0;
                }
            }
            // vertical
            for(int i = 0; i < range; i++){
                for(int j = 0; j < range - 14; j++ ){
                    for(int rule = 0; rule < 15; rule++){
                        if(rule3Model1[rule] == qrMatrixCopy[i][j+rule]) match++;  // сверяем элементы маски
                    }
                    // если совпала вся строка
                    if(match == 15){
                        penalty += 40;
                    }
                    match = 0;
                }
            }
            for(int i = 0; i < range; i++){
                for(int j = 0; j < range - 10; j++ ){
                    for(int rule = 0; rule < 11; rule++){
                        if(rule3Model2[rule] == qrMatrixCopy[i][j+rule]) match++;  // сверяем элементы маски
                        if(rule3Model3[rule] == qrMatrixCopy[i][j+rule]) match2++;
                    }
                    // если совпала вся строка
                    if((match == 11) ||(match2 == 11)){
                        penalty += 40;
                    }
                    match = 0;
                    match2 = 0;
                }
            }
            // rule 4
            int countBlackPixels = 0;
            for(int j = 0; j < range; j++){
                for(int i = 0; i < range; i++ ){
                    if(qrMatrixCopy[i][j] == 1) countBlackPixels++;
                }
            }
            float floatValue = float((countBlackPixels / countPixels * 100) - 50);
            int intValue = floatValue;
            if(intValue != 0){
                if(intValue < 0) intValue *= -1;
                floatValue = float(intValue) / 5;
                intValue = floatValue * 10;
                penalty += intValue;
            }

        }
        if(viewMask == 0) optimalPenalty = penalty;
        if(penalty <= optimalPenalty){
            optimalMask = viewMask;
            optimalPenalty = penalty;   // выбираем лучшую маску
        }
        viewMask++;         // выбираем следующую маску
        if(viewMask == 8) viewMask = optimalMask; // последняя генерация по оптимальной маске
    }

    qDebug()<<"Create image";
    // подгоняем размеры
    int w = range * 4 + 8;
    int h = w;
    /*int sizeImage = 24;
    float w = sizeImage;
    float h = sizeImage;
    float ran = range;
    float balance = float(sizeImage / ran);
    int balanceInt = sizeImage / ran;
    if(balance != 0){
        if(balance > 4){
            balanceInt *= ran;
            balanceInt = sizeImage - balanceInt;
            w = sizeImage - balanceInt;
        }else{
            w = ran * 4;
        }
    }

    balance = float(sizeImage / ran);
    balanceInt = sizeImage / ran;
    if(balance != 0){
        if(balance > 4){
            balanceInt *= ran;
            balanceInt = sizeImage - balanceInt;
            h = sizeImage - balanceInt;
        }else{
            h = ran * 4;
        }
    }*/

    pix = new QPixmap(w, h);
    pix->fill(Qt::white);
    /*w = w / ran;
    h = h / ran;
    // допустимое минимальное значение 4 пикселя
    if(w < 4 || h < 4) return -1;*/

    h = w = 4;
    paint.begin(pix);

    for(int i = 0; i < range; i++){
        for(int j = 0; j < range; j++){
            if(qrMatrixCopy[i][j] == 1) paint.fillRect(i*w+4,j*h+4,w,h,Qt::black);
            //if(qrMatrixCopy[i][j] == 0) paint.fillRect(i*w,j*h,w,h,Qt::white);
        }
    }
    paint.end();

    // освобождение памяти
    for(int i = 0; i < range; i++){
        delete[] qrMatrix[i];
        delete[] qrMatrixCopy[i];
    }
    delete qrMatrix;
    delete qrMatrixCopy;

    return 0;
}

QString GenQRCode::getImagePath() const{

    QString fileName = QString::number(QDateTime::currentDateTime().toMSecsSinceEpoch()) + ".png";

    QDir mDir;
    QString absolutePath(mDir.absolutePath() + QDir::separator() + "images" + QDir::separator() + fileName);
    pix->save(absolutePath, "PNG");

    return absolutePath;
}

// расчет по выбранной маске
int GenQRCode::ChoiceMask(const int &n, const int &i, const int &j) {

    switch (n) {
    case 0:
        return (j + i) % 2;
    case 1:
        return (j % 2);
    case 2:
        return (i % 3);
    case 3:
        return (j + i) % 3;
    case 4:
        return ((j / 2) + (i / 3)) % 2;
    case 5:
        return ((j * i) % 2) + ((j * i) % 3);
    case 6:
        return (((j * i) % 2) + ((j * i) % 3)) % 2;
    case 7:
        return (((j + i) % 2) + ((j * i) % 3)) % 2;
    default:
        return 1;
    }
}
